package lexical.domain;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ErrorLogger {
	List<LexicalError> errors = new ArrayList<LexicalError>();

	// Error patterns
	private Pattern unclosedString = Pattern.compile("\".*");
	private Pattern unclosedChar = Pattern.compile("\'.?");
	private Pattern charError = Pattern.compile("\'.{2,}'");

	public void log(String token, Integer lineNo) {
		String message = getErrorMessage(token);
		errors.add(new LexicalError(token, lineNo, message));
	}

	/**
	 * Returns an appropriate error message for the erroneous token.
	 * 
	 * @param token
	 * @return error message
	 */
	private String getErrorMessage(String token) {
		Matcher matcher;
		matcher = unclosedString.matcher(token);
		if(matcher.matches()){
			return "Unclosed string";
		}
		
		matcher = unclosedChar.matcher(token);
		if(matcher.matches()){
			return "Unclosed char";
		}
		
		matcher = charError.matcher(token);
		if(matcher.matches()){
			return "Invalid char declaration";
		}
		
		return "Invalid token";
	}

	public void print(PrintStream printer) {
		printer.println("#################################################");
		printer.println("########## Lexical Errors ##########");
		printer.println("#################################################");
		printer.println();
		printer.println(errors.size() + " lexical error(s) found.");
		int count = 1;
		for (LexicalError error : errors) {
			printer.println(String.format(
					"%d.Error on line:%d, token:%s, message:%s.", count,
					error.getLine(), error.getToken(), error.getMessage()));
			count++;
		}
	}

	private class LexicalError {
		private String token;
		private Integer line;
		private String message;

		public LexicalError() {
		}

		public LexicalError(String token, Integer line, String message) {
			super();
			this.token = token;
			this.line = line;
			this.message = message;
		}

		public String getToken() {
			return token;
		}

		public void setToken(String token) {
			this.token = token;
		}

		public Integer getLine() {
			return line;
		}

		public void setLine(Integer line) {
			this.line = line;
		}

		public String getMessage() {
			return message;
		}

		public void setMessage(String message) {
			this.message = message;
		}

	}
}
